#include "DistCaPProtocol.hpp"
#include <unistd.h>

DistCaPProtocol::DistCaPProtocol(int sck) throw(DistCaPProtocolException)
{
	my_socket = sck;
}

int DistCaPProtocol::startHandshake(unsigned int n_eval, unsigned int simSteps, float minStartAngle, float maxStartAngle) throw(DistCaPProtocolException)
{
	handshake_header hh;
	StandardPacket sp;

	//hh.rows = rows; hh.cols=cols; hh.lb = lb; hh.n_ing = n_ing; hh.n_op = n_op;
	hh.n_eval		 = n_eval;
	hh.simSteps		 = simSteps;
	hh.minStartAngle = minStartAngle;
	hh.maxStartAngle = maxStartAngle;

	if(write(my_socket,&hh,sizeof(handshake_header))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::startHandshake: Impossibile inviare Handshake header");

	memset(&sp,0,sizeof(StandardPacket));

	if(read(my_socket,&sp,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::startHandshake: Impossibile leggere Handshake Reply");

	if(sp.P_Type==PK_TYPE_CONFIRM && sp.payload.IntPayload == 1)
		return 1;
	else
		return 0;
}

int DistCaPProtocol::waitHandshake(GAmodSettings &settings) throw(DistCaPProtocolException)
{
	handshake_header hh;
	StandardPacket sp;

	//GAmodStrSetting *tgs;
	GAmodObjWrapper *tgs;
	string stringa;
	char str[255];

	if(read(my_socket,&hh,sizeof(handshake_header))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::waitHandshake: Impossibile leggere Handshake Header");

	sprintf(str,"%d",hh.simSteps);
	stringa.assign(str);
	tgs = new TemplateGAmodObjWrapper<string>(stringa);
	settings.add_setting("simSteps", tgs);

	sprintf(str,"%d",hh.n_eval);
	stringa.assign(str);
	tgs = new TemplateGAmodObjWrapper<string>(stringa);
	settings.add_setting("n_eval", tgs);

	sprintf(str,"%d",(int)hh.minStartAngle);
	stringa.assign(str);
	tgs = new TemplateGAmodObjWrapper<string>(stringa);
	settings.add_setting("minStartAngle", tgs);

	sprintf(str,"%d",(int)hh.maxStartAngle);
	stringa.assign(str);
	tgs = new TemplateGAmodObjWrapper<string>(stringa);
	settings.add_setting("maxStartAngle", tgs);

	memset(&sp,0,sizeof(StandardPacket));
	sp.P_Type = PK_TYPE_CONFIRM;
	/*if(hh.rows != rows || hh.cols!=cols || hh.lb!=lb || hh.n_ing != n_ing || hh.n_op != n_op)
		sp.payload.IntPayload = 0;
	else*/
		sp.payload.IntPayload = 1;

	if(write(my_socket,&sp,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::startHandshake: Impossibile inviare Handshake Reply");

	return sp.payload.IntPayload;
}

void DistCaPProtocol::waitPacket(StandardPacket &pckt) throw(DistCaPProtocolException)
{
	if(read(my_socket,&pckt,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::waitPacket: Errore lettura StandarPacket");

	return;
}

void DistCaPProtocol::sendPacket(StandardPacket &pckt) throw(DistCaPProtocolException)
{
	if(write(my_socket,&pckt,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::sendPacket: Errore scrittura StandarPacket");

	return;
}

void DistCaPProtocol::sendConfirm(int val) throw(DistCaPProtocolException)
{
	StandardPacket sp;

	sp.P_Type = PK_TYPE_CONFIRM;
	sp.payload.IntPayload = val;

	if(write(my_socket,&sp,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::sendConfirm: Errore invio conferma");

	return;
}

void DistCaPProtocol::getEvals(Popolazione *pop, int from, int to) throw(DistCaPProtocolException)
{
	int i;
	int dl,ndl;
	unsigned char *actVal;

	//printf("Evals[%d,%d] = [",from,to);

	for(i=from; i<=to; i++)
	{

		dl = 0;
		actVal = (unsigned char*)&((*pop)[i].fitness);
		do
		{
			if ((ndl=read(my_socket,actVal,sizeof(unsigned int)-dl)) == -1 )
				throw DistCaPProtocolException("DistCaPProtocol::getEvals: read fitness");
			else
				if(ndl!=sizeof(unsigned int)-dl)
				{
					printf("DistCaPProtocol::getEvals: read fitness OVERRUN [%d,%d]\n",ndl,sizeof(unsigned int)-dl);
				}
			dl+=ndl;
			actVal+=ndl;
		} while(dl<sizeof(unsigned int));

		//printf("%d ", ((*pop)[i].fitness));

		(*pop)[i].mod = 0;

		//if(read(my_socket,&((*pop)[i].fitness),sizeof(unsigned int))==-1)
		//	throw DistCaPProtocolException("DistCaPProtocol::getEvals: Errore ricezione valutazioni");
		write(my_socket,&i,sizeof(int));
	}
	//printf("]\n");
}

int DistCaPProtocol::waitConfirm() throw(DistCaPProtocolException)
{
	StandardPacket sp;

	sp.P_Type = PK_TYPE_CONFIRM;

	if(read(my_socket,&sp,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::waitConfirm: Errore wait conferma");

	if(sp.P_Type!=PK_TYPE_CONFIRM)
		throw DistCaPProtocolException("DistCaPProtocol::waitConfirm: Pacchetto di conferma errato");

	return sp.payload.IntPayload;
}

void DistCaPProtocol::sendEvals(Popolazione *pop) throw(DistCaPProtocolException)
{
	int i,n=0;

	for(i=0; i<pop->get_size(); i++)
	{
		if(write(my_socket,&((*pop)[i].fitness),sizeof(unsigned int))==-1)
			throw DistCaPProtocolException("DistCaPProtocol::sendEvals: Errore invio valutazioni");
		read(my_socket,&n,sizeof(int)); //Inserire controllo
	}
}

int DistCaPProtocol::startShutdown() throw(DistCaPProtocolException)
{
	StandardPacket pck;

	pck.P_Type = PK_TYPE_END;
	if(write(my_socket,&pck,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::startShutdown: Errore scrittura StandarPacket");

	if(read(my_socket,&pck,sizeof(StandardPacket))==-1)
		throw DistCaPProtocolException("DistCaPProtocol::startShutdown: Errore lettura StandarPacket");

	if(pck.P_Type==PK_TYPE_END)
	{
		try {
			sendConfirm(1);
			close(my_socket);
		}
		catch (DistCaPProtocolException &e) {
			throw e;
		}
		return 1;
	}
	IF_DBG_INFO(printf("[ERROR] DistCaPProtocol::startShutdown: Shutdown non confermato.");)
	return 0;
}
